﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Data.SQLite;

namespace Bald.KeypressCounter {
    public partial class MainForm : Form {
        public MainForm() {
            InitializeComponent();
        }
        public static int KeysCount = 0;
        private const int WH_KEYBOARD_LL = 13;
        private const int WM_KEYDOWN = 0x0100;
        private static LowLevelKeyboardProc _proc = HookCallback;
        private static IntPtr _hookID = IntPtr.Zero;

        private string connString = @"Data Source=" + Environment.CurrentDirectory + "\\data.db";
        private String userName = Environment.UserName;
        private void Form1_Load(object sender, EventArgs e) {
            this.Visible = false;
            notifyIcon.ContextMenuStrip = contextMenuStrip1;
            notifyIcon.BalloonTipText = "Начинаю считать нажатия клавиш";
            notifyIcon.ShowBalloonTip(1);
            readStatFromDb();
            startCollectClicks();
        }

        private void readStatFromDb() {
            // открываем sqlite базу
            
            SQLiteConnection conn = new SQLiteConnection(connString);
            conn.Open();
            String now = DateTime.Now.ToString("yyyy-MM-dd");
            SQLiteCommand cmd = new SQLiteCommand("select * from stat where user = @user and date=@date;", conn);
            cmd.Parameters.Add(new SQLiteParameter("@user", this.userName));
            cmd.Parameters.Add(new SQLiteParameter("@date", now));
            SQLiteDataReader reader = cmd.ExecuteReader();
            if(reader.Read()) {
                MainForm.KeysCount = (int)(long)reader["value"];
            }
            conn.Close();

        }

        private void startCollectClicks() {
            _hookID = SetHook(_proc);
        }

        private void exit_Click(object sender, EventArgs e) {
            Application.Exit();
        }

        private void showStats_Click(object sender, EventArgs e) {
            new StatForm().Show();
        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e) {
            UnhookWindowsHookEx(_hookID);
            writeStatDoDb();
        }

        private void writeStatDoDb() {
            SQLiteConnection conn = new SQLiteConnection(connString);
            conn.Open();
            String now = DateTime.Now.ToString("yyyy-MM-dd");
            SQLiteCommand cmd = new SQLiteCommand("select count(*) from stat where user = @user and date=@date;", conn);
            cmd.Parameters.Add(new SQLiteParameter("@user", this.userName));
            cmd.Parameters.Add(new SQLiteParameter("@date", now));
            long count = (long) cmd.ExecuteScalar();
            cmd.Dispose();
            if (count==1) {
                cmd = new SQLiteCommand("update stat set value=value + @value where user = @user and date=@date;", conn);
            } else {
                cmd = new SQLiteCommand("insert into stat(user, date, value) values(@user, @date, @value);", conn);
            }
            cmd.Parameters.Add(new SQLiteParameter("@user", this.userName));
            cmd.Parameters.Add(new SQLiteParameter("@date", now));
            cmd.Parameters.Add(new SQLiteParameter("@value", MainForm.KeysCount));
            cmd.ExecuteNonQuery();
            conn.Close();
        }
        private static IntPtr SetHook(LowLevelKeyboardProc proc) {
            using (Process curProcess = Process.GetCurrentProcess())
            using (ProcessModule curModule = curProcess.MainModule) {
                return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
                    GetModuleHandle(curModule.ModuleName), 0);
            }
        }

        private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
        private static int lastKeyCode = -1;
        private static int lastSomePressCount = 0;
        private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) {
            if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN) {
                int code = Marshal.ReadInt32(lParam);
                if (code == lastKeyCode) {
                    lastSomePressCount++;
                } else {
                    lastSomePressCount = 1;
                    lastKeyCode = code;
                }
                if (lastSomePressCount <= 3) {
                    KeysCount++;
                }
            }
            return CallNextHookEx(_hookID, nCode, wParam, lParam);
        }

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr SetWindowsHookEx(int idHook,
            LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool UnhookWindowsHookEx(IntPtr hhk);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
            IntPtr wParam, IntPtr lParam);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr GetModuleHandle(string lpModuleName);

        private void notifyIcon_MouseClick(object sender, MouseEventArgs e) {
            if (e.Button == System.Windows.Forms.MouseButtons.Left) {
                new StatForm().Show();
            }
        }

        private void notifyIcon_MouseMove(object sender, MouseEventArgs e) {
            notifyIcon.Text = this.userName + " нажал за " + DateTime.Now.ToLongDateString() + " кнопок: " + KeysCount;
        }

    }
}
